package org.ku.hero.codec;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.util.internal.logging.InternalLogger;
import io.netty.util.internal.logging.Slf4JLoggerFactory;
import org.ku.hero.api.protocol.Command;
import org.ku.hero.api.protocol.Const;
import org.ku.hero.api.protocol.Packet;

import java.nio.charset.StandardCharsets;

/** 协议解析
 * @author: yuez
 * @date: 2019/5/23 21:22
 */
public class PacketDecoder extends LengthFieldBasedFrameDecoder {
    private static final InternalLogger log = Slf4JLoggerFactory.getInstance(PacketDecoder.class);

    public PacketDecoder(int maxFrameLength, int lengthFieldOffset, int lengthFieldLength) {
        super(maxFrameLength, lengthFieldOffset, lengthFieldLength);
    }

    @Override
    protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {

        ByteBuf frame = (ByteBuf) super.decode(ctx,in);
        if (frame == null){
            return null;
        }
        //先寻找起始符
        ByteBuf ss = in.readBytes(2);
        if (!Const.SD_STR.equals(new String(ss.array(), StandardCharsets.UTF_8))){
            log.info("起始符错误,消息忽略");
            return null;
        }
        if (in.readableBytes() >= Packet.PACKAGE_MIN_LEN){
            //1.记录当前读取位置位置
            in.markReaderIndex();
            Packet packet = new Packet(Command.toCmd(in.readByte()));//命令标识
            packet.setAck(in.readByte());//应答标志
            packet.setVin(new String(in.readBytes(17).array(),StandardCharsets.UTF_8));//vin
            packet.setEncry(in.readByte());//加密方式
            packet.setLength(Short.toUnsignedInt(in.readShort()));//数据单元长度
            packet.setBody(in.readBytes(packet.getLength()).array());//数据
            packet.setCrc(in.readByte());//校验码
            boolean res = packet.valid2BCC();
            if (res){
                return packet;
            }
            log.info("消息校验不通过,消息忽略");
        }
        return null;
    }
}

